/** @file This file provides macros for timed waiting.  The wait time
 * and method for waiting may be configured by the user */
#ifndef __TIMED_WAIT_H_
#define __TIMED_WAIT_H_



/** @defgroup timed_wait_macros  Macros for timed waiting
 *
 *  These macros provide time limited waiting for a logical condition.
 * Usage:
 * \code
 *    //Tdelayms is a predefined method that waits for 1ms at a time.
 *    WAIT_WHILE( port_busy(),  10,  Tdelayms);
 *    if (port_busy()) { 
 *       // Timeout has occurred.
 *    }
 *   
 *    // Another usage pattern
 *    // TNULL is a predefined method that just waits for ever.  
 *     
 *    WAIT_UNTIL( module_available(), 1, TNULL);
 *
 * \endcode
 *
 *  There are a couple of pre-defined methods but the user can add
 *  user-defined methods.
 * <BR>
 * However, the real power of this is that code can be written once as
 * \code
 *    WAIT_WHILE(my_port_busy(), MY_PORT_BUSY_TIMEOUT, MY_PORT_BUSY_METHOD);
 * \endcode
 *  and the actual timeout and method to be used for busy waiting can
 *  be left in a configuration file to be changed later.
 * \code
 *   #define MY_PORT_BUSY_TIMEOUT   10
 *   #define MY_PORT_BUSY_TIMEOUT   Tdelayms
 * \endcode
 * <BR>
 *  For user defined wait times, the following macros have to exist
 *  (they can be null)
 *  TIME_INIT_[user_defined_name] (time_condition)
 *  TIME_CHECK_[user_defined_name] (time_condition)
 */



/** Wait while logical_cond is true.
 * @param logical_cond The logical condition
 * @param time_condition How long to wait
 * @param method         What type of wait method to use */
#define WAIT_WHILE(logical_cond, time_condition, method) \
	{                           \
		TINIT(method, time_condition);						\
		while( (logical_cond) && TCHECK(method, time_condition) ){} \
	}


#define WAIT_UNTIL(logical_cond, time_condition, method) \
	{                           \
		TINIT(method, time_condition);						\
		while( (!(logical_cond)) && TCHECK(method, time_condition) ){} \
	}

/*lint -emacro(506,TCHECK) */
/** The time initialization macro is constructed thus */
#define TINIT(method, time_condition)   TIME_INIT_ ##  method (time_condition)
/** The time checking method */
#define TCHECK(method, time_condition)   TIME_CHECK_ ## method (time_condition)



/** Null time check, no check performed */
#define TIME_CHECK_TNULL(time_condition)    (1)
/** Initialization for null time check method */
#define TIME_INIT_TNULL(time_condition)  






/* ============================================================
 * Other predefined time checks 
 * ------------------------------------------------------------ */

#define TIME_CHECK_1( time_condition )   (TBR < time_condition ? 1 : 0)
#define TIME_INIT_1(time_condition)     TBR = 0;


/* ------------------------------------------------------------*
 *  Wait periodically and check for condition every ms 
 * ------------------------------------------------------------*/
#include <util.h>

#define TIME_INIT_Tdelayms(time_condition) uint16_t target_delay = time_condition;  
#define TIME_CHECK_Tdelayms( time_condition)  (target_delay = timed_wait_delay1ms(target_delay))

/** Delay for one ms
 * @param target_delay The target delay time
 * @return The delay time remaining */
static inline  uint16_t timed_wait_delay1ms(uint16_t target_delay)
{
	delayms(1);
	target_delay--;
	return target_delay;
}
/* ------------------------------------------------------------*/


/* ------------------------------------------------------------
 *  Wait periodically and check for condition every 100us 
 * ------------------------------------------------------------*/
#include <util.h>
#define TIME_INIT_Tdelay100us(time_condition) uint16_t target_delay = time_condition;  
#define TIME_CHECK_Tdelay100us( time_condition)  (target_delay = timed_wait_delay100us(target_delay))
/** Delay for 100 us
 * @param target_delay The target delay time
 * @return The delay time remaining */
static inline  uint16_t timed_wait_delay100us(uint16_t target_delay)
{
	delayus(100);
	target_delay--;
	return target_delay;
}

/* ------------------------------------------------------------*/



/* ============================================================ */





#endif
